package terrain.impl.first;

import interfaces.WorldInterface;
import interfaces.WorldNodeInterface;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.geom.Arc2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;


import objects.ImageObject;

import extra.Position;
import factory.ConstantsFactory;
import factory.WorldNodeInterfaceFactory;
import graph.NodeArc;
import graph.NodeWorld;


public class WorldFirst implements WorldInterface{
	
	
	private int height;
	private int width;
	private WorldNodeInterface world[][];
	
	public WorldFirst(int width, int height){
		this.width=width;
		this.height=height;
		
		world = new WorldNodeInterface [width] [height];
		for(int i=0;i<width;i++){
			for(int j=0;j<height;j++){
				world[i][j]= WorldNodeInterfaceFactory.createNewWorldNodeInterface(ConstantsFactory.WORLD_NODE_FIRST);
				world[i][j].setPosition(new Position(i*ConstantsFirst.NODE_WIDTH, j*ConstantsFirst.NODE_HEIGHT));
			}
		}
		
		
	}
	
	@Override
	public void newWorld(int width, int height) {
		
		new WorldFirst(width, height);
		
	}
	
	@Override
	public WorldNodeInterface getNode(Position position) {
			
		int x = (int) position.getX()/ConstantsFirst.NODE_WIDTH;
		int y = (int) position.getY()/ConstantsFirst.NODE_HEIGHT;
		
		if(x<0)
			x=0;
		if(x>=width)
			x=width-1;
		if(y<0)
			y=0;
		if(y>=height)
			y=height-1;
		
		return world[x][y];
	}

	@Override
	public ArrayList<WorldNodeInterface> getAdjacents(Position position) {
		int x = (int) position.getX()/ConstantsFirst.NODE_WIDTH;
		int y = (int) position.getY()/ConstantsFirst.NODE_HEIGHT;
		
		if(x<0)
			x=0;
		if(x>=width)
			x=width-1;
		if(y<0)
			y=0;
		if(y>height)
			y=height-1;
		
		ArrayList<WorldNodeInterface> nodeList = new ArrayList<WorldNodeInterface>();
		
		if(x-1>=0){
			nodeList.add(world[x-1][y]);
			if(y-1>=0){
				nodeList.add(world[x-1][y-1]);
			}
			if(y+1<height){
				nodeList.add(world[x-1][y+1]);
			}
		}
		if(x+1<width){
			nodeList.add(world[x+1][y]);
			if(y-1>=0){
				nodeList.add(world[x+1][y-1]);
			}
			if(y+1<height){
				nodeList.add(world[x+1][y+1]);
			}
		}
		if(y+1<height){
			nodeList.add(world[x][y+1]);
		}
		if(y-1>=0){
			nodeList.add(world[x][y-1]);
		}
		
		return nodeList;
	}

	@Override
	public ArrayList<WorldNodeInterface> getAdjacents(WorldNodeInterface node) {	
		return getAdjacents(node.getPosition());
	}

	@Override
	public void calculateCollision(ImageObject collisionImage) {
		
		Position pos = collisionImage.getPosition();
		int x = (int) pos.getX()/ConstantsFirst.NODE_WIDTH;
		int y = (int) pos.getY()/ConstantsFirst.NODE_HEIGHT;
		
		if(x<0)
			x=0;
		if(x>=width)
			x=width;
		if(y<0)
			y=0;
		if(y>height)
			y=height;
		
		int xFinal = (int) (pos.getX() + collisionImage.getCollisionShape().getWidth())/ConstantsFirst.NODE_WIDTH;
		int yFinal = (int) (pos.getY() + collisionImage.getCollisionShape().getHeight())/ConstantsFirst.NODE_HEIGHT;
		

		if(xFinal<0)
			xFinal=0;
		if(xFinal>=width)
			xFinal=width;
		if(yFinal<0)
			yFinal=0;
		if(yFinal>=height)
			yFinal=height;
		
		if(yFinal==height)
			yFinal=height-1;
		if(xFinal==width)
			xFinal=width-1;
		
		for(int i=x;i<=xFinal;i++){
			for(int j=y;j<=yFinal;j++){
				//System.out.println("Busco Colision First i "+i+" j "+j );
				world[i][j].calculateCollision(collisionImage);
			}
		}
		
	}


	

	@Override
	public ArrayList<WorldNodeInterface> getFreeAdjacents(Position position) {
		
		int x = (int) position.getX()/ConstantsFirst.NODE_WIDTH;
		int y = (int) position.getY()/ConstantsFirst.NODE_HEIGHT;
		
		if(x<0)
			x=0;
		if(x>=width)
			x=width-1;
		if(y<0)
			y=0;
		if(y>height)
			y=height;
		
		ArrayList<WorldNodeInterface> nodeList = new ArrayList<WorldNodeInterface>();
		
		if(x-1>=0){
			if(world[x-1][y].isFree()){
				nodeList.add(world[x-1][y]);
			}
			if(y-1>=0){
				if(world[x-1][y-1].isFree()){
					nodeList.add(world[x-1][y-1]);
				}
			}
			if(y+1<height){
				if(world[x-1][y+1].isFree()){
					nodeList.add(world[x-1][y+1]);
				}
			}
		}
		if(x+1<width){
			if(world[x+1][y].isFree()){
				nodeList.add(world[x+1][y]);
			}
			if(y-1>=0){
				if(world[x+1][y-1].isFree()){
					nodeList.add(world[x+1][y-1]);
				}
			}
			if(y+1<height){
				if(world[x+1][y+1].isFree()){
					nodeList.add(world[x+1][y+1]);
				}
			}
		}
		if(y+1<height){
			if(world[x][y+1].isFree()){
				nodeList.add(world[x][y+1]);
			}
		}
		if(y-1>=0){
			if(world[x][y-1].isFree()){
				nodeList.add(world[x][y-1]);
			}
		}
		
		return nodeList;
		
	}

	@Override
	public ArrayList<WorldNodeInterface> getFreeAdjacents(
			WorldNodeInterface node) {

		return getFreeAdjacents(node.getPosition());
	}

	@Override
	public boolean isFree(Position position) {
		
		int x = (int) position.getX()/ConstantsFirst.NODE_WIDTH;
		int y = (int) position.getY()/ConstantsFirst.NODE_HEIGHT;
		
		if(x<0)
			x=0;
		if(x>=width)
			x=width-1;
		if(y<0)
			y=0;
		if(y>=height)
			y=height-1;
		
		return world[x][y].isFree();
	}

	@Override
	public boolean isFree(WorldNodeInterface node) {

		return isFree(node.getPosition());
	}

	@Override
	public int getHeigth() {

		return height;
	}

	@Override
	public int getWidth() {

		return width;
	}

	@Override
	public void paint(Graphics g) {
		
		
		for(int i=0;i<width;i++){
			for(int j=0;j<height;j++){
				world[i][j].paint(g);
			}
		}
		
	}

	@Override
	public NodeWorld generateGraph(Position position, int depthNumber) {
		
		//NodeWorld root = new NodeWorld(getNode(position));
		NodeWorld root=null;
		
		int x = (int) position.getX()/ConstantsFirst.NODE_WIDTH;
		int y = (int) position.getY()/ConstantsFirst.NODE_HEIGHT;
		
		int beginX = x-(depthNumber);
		int endX   = x+(depthNumber);
		
		int beginY = y-(depthNumber);
		int endY   = y+(depthNumber);
		
		if(beginX<0)
			beginX=0;
		if(beginX>width)
			beginX=width;
		if(beginY<0)
			beginY=0;
		if(beginY>width)
			beginY=width;

		if(endX<0)
			endX=0;
		if(endX>width)
			endX=width;
		if(endY<0)
			endY=0;
		if(endY>width)
			endY=width;
		
		NodeWorld matrix[][] = new NodeWorld[depthNumber*2][depthNumber*2];
		
		//System.out.println("xbegin "+beginX+" xend "+endX+" begin y "+beginY+" endy "+endY);
		
		int k=0,l=0;
		
		for(int i=beginX;i<endX;i++){
			l=0;
			for(int j= beginY; j<endY; j++){
				
				if(i==x && j==y){
					root = new NodeWorld(world[i][j]);
					matrix[k][l]=root;
					//System.out.println("Encontre nodo root First");
				}
				else{
				matrix[k][l] = new NodeWorld(world[i][j]);
				}
				l++;
			}
			k++;
		}
		//now i fill the arcs
		NodeArc arc;
		int distance = ConstantsFirst.NODE_WIDTH;
		int diagonalDistance = (int) Math.sqrt(Math.pow(distance, 2)+Math.pow(distance, 2));
		for(int i=0;i<k;i++){
			for(int j= 0; j<l; j++){
				
				
				if(i-1>=0){
					arc= new NodeArc(matrix[i][j], matrix[i-1][j], distance);
					matrix[i][j].addArc(arc);
					if(j-1>=0){
						arc= new NodeArc(matrix[i][j], matrix[i-1][j-1], diagonalDistance);
						matrix[i][j].addArc(arc);
					}
					if(j+1<l){
						arc= new NodeArc(matrix[i][j], matrix[i-1][j+1], diagonalDistance);
						matrix[i][j].addArc(arc);
					}
				}
				if(i+1<k){
					arc= new NodeArc(matrix[i][j], matrix[i+1][j], distance);
					matrix[i][j].addArc(arc);
					
					if(j-1>=0){
						arc= new NodeArc(matrix[i][j], matrix[i+1][j-1], diagonalDistance);
						matrix[i][j].addArc(arc);
						
					}
					if(j+1<l){
						arc= new NodeArc(matrix[i][j], matrix[i+1][j+1], diagonalDistance);
						matrix[i][j].addArc(arc);
					}
				}
				if(j+1<l){
					arc= new NodeArc(matrix[i][j], matrix[i][j+1], distance);
					matrix[i][j].addArc(arc);
					
				}
				if(j-1>=0){
					arc= new NodeArc(matrix[i][j], matrix[i][j-1], distance);
					matrix[i][j].addArc(arc);
					
				}
				
			}
		}
		
		
		//System.out.println(" TAM FIRST "+root.getArcList().size());
		
		return root;
	}

	@Override
	public boolean isInside(Position position) {
		int x = (int) position.getX()/ConstantsFirst.NODE_WIDTH;
		int y = (int) position.getY()/ConstantsFirst.NODE_HEIGHT;
		if( x<0 || x>=width || y<0 || y>=height){
			return false;
		}
		return true;		
		
	}

	@Override
	public void freeCollisionsNodes() {
		for(int i=0;i<width;i++){
			for(int j=0;j<height;j++){
				world[i][j].setIsFree(true);
			}
		}
		
	}

	
	
	
}
